package com.dhf.framework.common;

import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import javax.validation.Validator;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.dhf.framework.base.utils.AjaxUtil;
import com.dhf.framework.base.utils.BeanValidators;
import com.dhf.framework.base.utils.DateUtils;
import com.dhf.framework.base.utils.ResponseData;
import com.dhf.framework.system.entity.SysUser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;


/**
 * 
* @ClassName: BaseController
* @Description: 公共基础Controller
* @author HoraceHo
*
 */
abstract public class BaseController {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	public final static String EXCEPTION_MESSAGE = "EXCEPTION_MESSAGE";
	
	public final ObjectMapper mapper = new ObjectMapper();

	@Autowired
	private Validator validator;

    /**
     * 服务端参数有效性验证
     * @param object 验证的实体对象
     * @param groups 验证组
     * @return 验证成功：返回true；严重失败：将错误信息添加到 message 中
     */
	public boolean beanValidator(ModelAndView modelAndView, Object object, Class<?>... groups) {
        try{
            BeanValidators.validateWithException(validator, object, groups);
        }catch(ConstraintViolationException ex){
            List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
            list.add(0, "数据验证失败：");
            addMessage(modelAndView, list.toArray(new String[]{}));
            return false;
        }
        return true;
    }
	
	
	/**
     * 初始化数据绑定
     * 1. 将所有传递进来的String进行HTML编码，防止XSS攻击
     * 2. 将字段中Date类型转换为String类型
     */
	@InitBinder
	public void initBinder(WebDataBinder binder) {
	    // String类型转换，将所有传递进来的String进行HTML编码，防止XSS攻击
        binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) {
                setValue(text == null ? null : StringEscapeUtils.escapeHtml4(text.trim()));
            }
            @Override
            public String getAsText() {
                Object value = getValue();
                return value != null ? value.toString() : "";
            }
        });
        // Date 类型转换
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) {
                setValue(DateUtils.parseDate(text));
            }
        });
	    
//        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        dateFormat.setLenient(false);
//        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }
	
	/**
     * 参数绑定异常
     */
    @ExceptionHandler({BindException.class, ConstraintViolationException.class, ValidationException.class})
    public String bindException() {  
        return "error/400";
    }
	
	
	@ExceptionHandler()
	public void handleException(Exception exception, HttpServletRequest request, HttpServletResponse response) {
		//服务端处理失败
		response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
		request.setAttribute(EXCEPTION_MESSAGE, exception);
		
		logger.error(exception.getMessage(), exception);
		logger.debug(this.getClass()+"--"+exception.getMessage());
		if(!AjaxUtil.isAjaxRequest(request)) {//form请求
			RequestDispatcher rd =  request.getSession().getServletContext().getRequestDispatcher("/error.do"); 
            try {
				rd.forward(request, response);
			} catch (Exception e) {
				logger.error(e.getMessage(),exception);
			}
		} else {//ajax请求
			ResponseData data = new ResponseData(false, exception.getClass() + ": " + exception.getMessage());
			data.setRequestURI(request.getRequestURI());
			data.setExecptionTrace(ExceptionUtils.getFullStackTrace(exception));
			try {
				String json = mapper.writeValueAsString(data);
				response.setContentType("application/json;charset=UTF-8");
				response.getOutputStream().print(json);
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}
	}
	
	/**
     * 得到User对象
     */
    public SysUser getUser() {
        HttpServletRequest httpRequest = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = httpRequest.getSession(true);
        //从session中获取用户信息
        SysUser user=(SysUser) session.getAttribute(Constants.SESSION_USER_KEY);
        return user;
    }
    
    /**
     * 添加Model消息
     * @param message
     */
    protected void addMessage(ModelAndView modelAndView, String... messages) {
        StringBuilder sb = new StringBuilder();
        for (String message : messages){
            sb.append(message).append(messages.length>1?"<br/>":"");
        }
        modelAndView.addObject("message", sb.toString());
    }
    
    /**
     * 添加Flash消息
     * @param message
     */
    protected void addMessage(RedirectAttributes redirectAttributes, String... messages) {
        StringBuilder sb = new StringBuilder();
        for (String message : messages){
            sb.append(message).append(messages.length>1?"<br/>":"");
        }
        redirectAttributes.addFlashAttribute("message", sb.toString());
    }
    
    /**
     * 客户端返回JSON字符串
     * @param response
     * @param object
     * @return
     * @throws JsonProcessingException 
     */
    protected String renderString(HttpServletResponse response, Object object) throws JsonProcessingException {
        return renderString(response, mapper.writeValueAsString(object), "application/json");
    }
    
    /**
     * 客户端返回字符串
     * @param response
     * @param string
     * @return
     */
    protected String renderString(HttpServletResponse response, String string, String type) {
        try {
            response.reset();
            response.setContentType(type);
            response.setCharacterEncoding("utf-8");
            response.getWriter().print(string);
            return null;
        } catch (IOException e) {
            return null;
        }
    }

 
}
